using System;
using System.Collections.Generic;
using System.Linq;
using Heap;

namespace ArrayHeap {
    public class HeapFactory<T> : IHeapFactory<T> {

        public IHeap<T> CreateHeap(IComparer<T> comparer) {
            if(comparer==null)
                throw new ArgumentNullException("comparer");
            return new Heap<T>(comparer); 
        }

        public IHeap<T> CreateHeap<T1>(IEnumerable<T1> items, IComparer<T> comparer) where T1 : T {
            if (items == null)
                throw new ArgumentNullException("items");
            if (comparer == null)
                throw new ArgumentNullException("comparer");
            var elems = items as T1[] ?? items.ToArray();
            var heap = new Heap<T>(comparer, (uint)elems.Count());
            foreach (var elem in elems){
                heap.Insert(elem);
            }
            return heap;
        }

        public IHeap<T> Merge<T1, T2>(IComparer<T> comparer, IHeap<T1> heap1, params IHeap<T2>[] otherHeaps) where T1 : T where T2 : T {
            if (heap1 == null)
                throw new ArgumentNullException("heap1");
            if (comparer == null)
                throw new ArgumentNullException("comparer");
            var newHeap = CreateHeap(heap1, comparer);
            foreach (var heapElem in otherHeaps.SelectMany(heap => heap))
                newHeap.Insert(heapElem);
            return newHeap;
        }
    }

    public class HeapFactoryDefault<T> : HeapFactory<T>, IHeapFactoryDefault<T> where T: IComparable<T> {
        public IHeap<T> CreateHeap<T1>(IEnumerable<T1> items) where T1 : T {
            if (items == null)
                throw new ArgumentNullException("items");
            var comparer = Comparer<T>.Default;
            return CreateHeap(items, comparer);
            
        }

        public IHeap<T> CreateHeap() {
            var comparer = Comparer<T>.Default;
            return base.CreateHeap(comparer);
        }
    }
}